#include "../collections.h"
#include <stdlib.h>

list list_create()
{
	list self = malloc(sizeof(struct list));

	self->first = NULL;
	self->last = NULL;

	return self;
}

void list_delete(list self)
{
	list_clear(self);
	free(self);
	self = NULL;
}

void list_clear(list self)
{
	node aux = self->first;
	while (aux != NULL)
	{
		node toremove = aux;
		aux = node_getlink(aux);
		node_delete(toremove);
	}
	self->last = NULL;
	self->first = NULL;
}

void _list_append(list self, int T, void * value)
{
	node newnode = node_create(T, value, NULL);
	if (self->last != NULL)
		node_connect(self->last, newnode);

	self->last = newnode;

	if (self->first == NULL)
		self->first = newnode;
}

void _list_prepend(list self, int T, void * value)
{
	self->first = node_create(T, value, self->first);

	if (self->last == NULL)
		self->last = self->first;
}

int _list_read(list self, int T, int index, void * value)
{
	node target = _list_locate(self, index);

	if(target == NULL)
		return 0;

	node_read(target, T, value);
	return 1;
}

void _list_write(list self, int T, int index, void * value)
{
	node_write(_list_locate(self, index), T, value);
}

node _list_locate(list self, int index)
{
	node aux = self->first;
	while (index--)
	{
		if(aux == NULL)
			return NULL;
		aux = node_getlink(aux);
	}
	return aux;
}

int _list_contains(list self, int T, void * value, comparer comp)
{
	return _list_indexof(self, T, value, comp) != -1;
}

void list_removefirst(list self)
{
	node aux = self->first;
	self->first = node_getlink(aux);

	if(self->first == NULL)
		self->last = NULL;

	node_delete(aux);
}

void list_removeat(list self, int index)
{
	if(index == 0)
	{
		list_removefirst(self);
	}
	else
	{
		node prev = _list_locate(self, index - 1);
		node todelete = node_getlink(prev);

		if(todelete != NULL)
		{
			node_connect(prev, node_getlink(todelete));
		}
		node_delete(todelete);
	}
}

int list_count(list self)
{
	int count = 0;
	node aux = self->first;
	while(aux != NULL)
	{
		aux = node_getlink(aux);
		count++;
	}
	return count;
}

int list_isempty(list self)
{
	return self->first == NULL;
}

void list_removelast(list self)
{
	list_removeat(self, list_count(self) - 1);
}

void _list_readfirst(list self, int T, void * value)
{
	node_read(self->first, T, value);
}


void _list_readlast(list self, int T, void * value)
{
	node_read(self->last, T, value);
}

int _list_indexof(list self, int T, void * value, comparer comp)
{
	int current = 0;
	node aux = self->first;
	while(aux != NULL)
	{
		if(node_valueis(aux, T, value, comp))
			return current;
		else
		{
			aux = node_getlink(aux);
			current++;
		}
	}
	return -1;
}

void _list_insert(list self, int T, int index, void * value)
{
	if(index == 0)
	{
		_list_prepend(self, T, value);
	}
	else
	{
		node previous = _list_locate(self, index - 1);
		node next = node_getlink(previous);
		node newnode = node_create(T, value, next);
		node_connect(previous, newnode);
	}
}

